﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace WpfApp_MvvmIoc.Base;

public class CustomerIoc
{

    private static readonly object _locker = new object();

    private CustomerIoc() { }

    //private static CustomerIoc _Instance;
    //public static CustomerIoc Instance
    //{
    //    get 
    //    {
    //        if (_Instance == null)
    //        {
    //            lock (_locker)
    //            {
    //                if (_Instance == null) 
    //                {
    //                    _Instance = new CustomerIoc();
    //                }
    //            }
    //        }
    //        return _Instance;
    //    }
    //}

    //private static readonly Lazy<CustomerIoc> _lazy = new Lazy<CustomerIoc>(()=> new CustomerIoc());
    //private static CustomerIoc Instance => _lazy.Value;

    private static CustomerIoc Instance => Nested.customerIoc;
    private class Nested
    {
        static Nested() { }
        internal static readonly CustomerIoc customerIoc = new CustomerIoc();
    }


    private static Dictionary<string, InstanceModel> _instanceDic = new Dictionary<string, InstanceModel>();

    /// <summary>
    /// 注册类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static void Register<T>()
    {
        _instanceDic.Add(typeof(T).FullName!, new InstanceModel()
        {
            IsSingle = false,
            ObjectType = typeof(T),
            Instance = null
        });
    }

    /// <summary>
    /// 注册单例类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static void RegisterSingle<T>()
    {
        _instanceDic.Add(typeof(T).FullName!, new InstanceModel()
        {
            IsSingle = true,
            ObjectType = typeof(T),
            Instance = null
        });
    }

    /// <summary>
    /// 注册带接口的类
    /// </summary>
    /// <typeparam name="TInterfance"></typeparam>
    /// <typeparam name="TClass"></typeparam>
    public static void Register<TInterfance, TClass>() where TClass : TInterfance
    {
        _instanceDic.Add(typeof(TInterfance).FullName!, new InstanceModel()
        {
            IsSingle = false,
            ObjectType = typeof(TClass),
            Instance = null
        });
    }

    /// <summary>
    /// 注册带接口的单例类
    /// </summary>
    /// <typeparam name="TInterfance"></typeparam>
    /// <typeparam name="TClass"></typeparam>
    public static void RegisterSingle<TInterfance, TClass>() where TClass : TInterfance
    {
        _instanceDic.Add(typeof(TInterfance).FullName!, new InstanceModel()
        {
            IsSingle = true,
            ObjectType = typeof(TClass),
            Instance = null
        });
    }

    /// <summary>
    /// 获取实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static T GetInstance<T>()
    {
        string? fullName = typeof(T).FullName;
        if (string.IsNullOrEmpty(fullName))
            throw new Exception("获取实例名称异常！");
        if (!_instanceDic.ContainsKey(fullName))
            return default(T)!;
        InstanceModel instanceModel = _instanceDic[fullName];
        if (instanceModel.IsSingle)
        {
            if (instanceModel.Instance != null)
                return (T)instanceModel.Instance;
            else
            {
                object? instance = (T)CreateInstance(instanceModel.ObjectType);
                instanceModel.Instance = instance;
                return (T)instance;
            }
        }
        else
            return (T)CreateInstance(instanceModel.ObjectType);
    }

    /// <summary>
    /// 创建实例
    /// </summary>
    /// <param name="key"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    private static object CreateInstance(Type type)
    {
        ConstructorInfo[] constructorInfos = type.GetConstructors();
        ParameterInfo[] parameterInfos = constructorInfos[0].GetParameters();
        List<object> constructorParams = new List<object>();
        foreach (ParameterInfo item in parameterInfos)
        {
            string _paramName = item.ParameterType.FullName!;
            if (_instanceDic.ContainsKey(_paramName))
            {
                InstanceModel instanceModel = _instanceDic[_paramName];
                if (instanceModel.IsSingle)
                {
                    if (instanceModel.Instance == null)
                        instanceModel.Instance = CreateInstance(instanceModel.ObjectType);
                }else
                    instanceModel.Instance = CreateInstance(instanceModel.ObjectType);
                constructorParams.Add(instanceModel.Instance!);
            }
        }

        object? instance = Activator.CreateInstance(type, constructorParams.ToArray());
        if (instance == null)
            throw new Exception("创建对象失败！");


        PropertyInfo[] propertyInfos = type.GetProperties();
        foreach (var item in propertyInfos)
        {
            if (item.IsDefined(typeof(DependyAttribute), false))
            {
                string _paramName = item.PropertyType.FullName!;
                if (_instanceDic.ContainsKey(_paramName))
                {
                    InstanceModel instanceModel = _instanceDic[_paramName];
                    if (instanceModel.IsSingle)
                    {
                        if (instanceModel.Instance == null)
                            instanceModel.Instance = CreateInstance(instanceModel.ObjectType);
                    }
                    else
                        instanceModel.Instance = CreateInstance(instanceModel.ObjectType);
                    item.SetValue(instance, instanceModel.Instance);
                }
            }     
        }


        return instance;
    }
}

class InstanceModel
{
    public bool IsSingle { get; set; }
    public Type ObjectType { get; set; } = default(Type)!;
    public object? Instance { get; set; }
}


